﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using YanZhiwei.DotNet2.Utilities.Models;
namespace YanZhiwei.DotNet2.Utilities.Common
{
    /// <summary>
    /// 反射帮助类
    /// </summary>
    public static class ReflectHelper
    {
        static BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public |
                          BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
        #region 获取实体类[DisplayName]以及本身Name
        /// <summary>
        /// 获取实体类[DisplayName]以及本身Name
        /// </summary>
        /// <typeparam name="T">实体类</typeparam>
        /// <returns>IDictionary</returns>
        public static IDictionary<string, string> GetDisplayName<T>() where T : class
        {
            IDictionary<string, string> _fields = new Dictionary<string, string>();
            PropertyInfo[] _properties = typeof(T).GetProperties();
            int _properityCnt = _properties.Length;
            foreach (PropertyInfo property in _properties)
            {
                object[] _attribute = property.GetCustomAttributes(typeof(DisplayNameAttribute), false);
                _fields.Add(property.Name, _attribute.Length == 0 ? property.Name : ((DisplayNameAttribute)_attribute[0]).DisplayName);
            }
            return _fields;
        }
        #endregion
        #region 反射调用方法
        /// <summary>
        /// 反射调用方法
        /// </summary>
        /// <param name="obj">需反射类型</param>
        /// <param name="methodName">调用方法名称</param>
        /// <param name="args">参数</param>
        /// <returns></returns>
        public static object InvokeMethod(object obj, string methodName, object[] args)
        {
            object _objReturn = null;
            Type _type = obj.GetType();
            _objReturn = _type.InvokeMember(methodName, bindingFlags | BindingFlags.InvokeMethod, null, obj, args);
            return _objReturn;
        }
        #endregion
        #region 反射设置值
        /// <summary>
        /// 反射设置值
        /// </summary>
        /// <param name="obj">操作对象</param>
        /// <param name="name">名称</param>
        /// <param name="value">值</param>
        public static void SetField(object obj, string name, object value)
        {
            FieldInfo _fi = obj.GetType().GetField(name, bindingFlags);
            _fi.SetValue(obj, value);
        }
        #endregion
        #region 反射获取值
        /// <summary>
        /// 反射获取值
        /// </summary>
        /// <param name="obj">操作对象</param>
        /// <param name="name">需要获取值的名称</param>
        /// <returns>值</returns>
        public static object GetField(object obj, string name)
        {
            FieldInfo _fi = obj.GetType().GetField(name, bindingFlags);
            return _fi.GetValue(obj);
        }
        #endregion
        #region 利用反射来判断对象是否包含某个属性
        /// <summary>
        /// 利用反射来判断对象是否包含某个属性
        /// </summary>
        /// <param name="instance">object</param>
        /// <param name="propertyName">需要判断的属性</param>
        /// <returns>是否包含</returns>
        public static bool ContainProperty(this object instance, string propertyName)
        {
            if (instance != null && !string.IsNullOrEmpty(propertyName))
            {
                PropertyInfo _findedPropertyInfo = instance.GetType().GetProperty(propertyName);
                return (_findedPropertyInfo != null);
            }
            return false;
        }
        #endregion
        #region 对象Pulbic属性比较
        /// <summary>
        /// 对象Pulbic属性比较
        /// <para>参考：http://stackoverflow.com/questions/4951233/compare-two-objects-and-find-the-differences </para>
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="self">对象</param>
        /// <param name="to">需要比较的对象</param>
        /// <param name="ignore">忽略比较的属性名称</param>
        /// <returns>是否相等</returns>
        public static bool PublicInstancePropertiesEqual<T>(T self, T to, params string[] ignore) where T : class
        {
            if (self != null && to != null)
            {
                Type _type = typeof(T);
                List<string> _ignoreList = new List<string>(ignore);
                foreach (PropertyInfo pi in _type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (!_ignoreList.Contains(pi.Name))
                    {
                        string _propertyName = pi.Name;
                        object _selfValue = _type.GetProperty(_propertyName).GetValue(self, null);
                        object _toValue = _type.GetProperty(_propertyName).GetValue(to, null);
                        if (_selfValue != _toValue && (_selfValue == null || !_selfValue.Equals(_toValue)))
                        {
                            return false;
                        }
                    }
                }
                return true;
            }
            return self == to;
        }
        #endregion
        #region 获取对象Public属性比较差异集合
        /// <summary>
        /// 获取对象Public属性比较差异集合
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="self">对象</param>
        /// <param name="to">需要比较的对象</param>
        /// <param name="ignore">忽略比较的属性名称</param>
        /// <returns>差异集合</returns>
        public static List<Variance> DetailedPublicInstancePropertiesEqual<T>(T self, T to, params string[] ignore) where T : class
        {
            List<Variance> _variances = new List<Variance>();
            if (self != null && to != null)
            {
                Type _type = typeof(T);
                List<string> _ignoreList = new List<string>(ignore);
                foreach (PropertyInfo pi in _type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (!_ignoreList.Contains(pi.Name))
                    {
                        string _propertyName = pi.Name;
                        object _selfValue = _type.GetProperty(_propertyName).GetValue(self, null);
                        object _toValue = _type.GetProperty(_propertyName).GetValue(to, null);
                        if (_selfValue != _toValue && (_selfValue == null || !_selfValue.Equals(_toValue)))
                        {
                            _variances.Add(new Variance() { Key = _propertyName, Value = _toValue });
                        }
                    }
                }
            }
            return _variances;
        }
        /// <summary>
        /// 获取对象Public属性比较差异集合
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="self">对象</param>
        /// <param name="to">需要比较的对象</param>
        /// <param name="subKey">主键</param>
        /// <param name="ignore">忽略比较的属性名称</param>
        /// <returns>差异集合</returns>
        public static List<Variance> DetailedPublicInstancePropertiesEqual<T>(T self, T to, string subKey, params string[] ignore) where T : class
        {
            List<Variance> _variances = DetailedPublicInstancePropertiesEqual<T>(self, to, ignore);
            if (!string.IsNullOrEmpty(subKey))
            {
                foreach (Variance v in _variances)
                {
                    v.SubKey = subKey;
                }
            }
            return _variances;
        }
        #endregion
        #region 将实体类属性转换成键值对形式表述
        /// <summary>
        /// 将实体类属性转换成键值对形式表述
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="self">对象</param>
        /// <param name="subKey">主键</param>
        /// <param name="ignore">忽略比较的属性名称</param>
        /// <returns>键值对集合</returns>
        public static List<Variance> DetailedPublicInstanceProperties<T>(T self, string subKey, params string[] ignore) where T : class
        {
            List<Variance> _variances = new List<Variance>();
            if (self != null)
            {
                Type _type = typeof(T);
                List<string> _ignoreList = new List<string>(ignore);
                foreach (PropertyInfo pi in _type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (!_ignoreList.Contains(pi.Name))
                    {
                        string _propertyName = pi.Name;
                        object _propertyValue = _type.GetProperty(_propertyName).GetValue(self, null);
                        _variances.Add(new Variance() { Key = _propertyName, Value = _propertyValue, SubKey = subKey });
                    }
                }
            }
            return _variances;
        }
        #endregion 
    }
}